package com.yi.wood.web.service.impl;

import com.yi.wood.base.Result;
import com.yi.wood.base.ResultCodeEnum;
import com.yi.wood.entity.User;
import com.yi.wood.sequence.Snowflake;
import com.yi.wood.service.exception.BusinessException;
import com.yi.wood.service.impl.AbstractUserServiceImpl;
import com.yi.wood.service.po.UserCachePo;
import com.yi.wood.utils.StringTokenUtil;
import com.yi.wood.web.ctrl.dto.UserDto;
import com.yi.wood.web.service.UserProService;
import com.yi.wood.web.util.UserCacheUtil;
import org.springframework.beans.BeanUtils;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Objects;

/**
 * Created by moyi on 2019/4/4 17:31
 *
 * @author moyi
 */
@Service("userProService")
public class UserProServiceImpl extends AbstractUserServiceImpl implements UserProService {

    @Resource
    private UserCacheUtil userCacheUtil;

    @Resource
    private Snowflake snowflake;

    @Override
    public UserCachePo login(String username, String password) throws BusinessException {
        User user = findUserByUserName(username);
        if (Objects.isNull(user)) {
            throw new BusinessException(new Result(ResultCodeEnum.AUTH_FAILED, null));
        }
        UserCachePo userCachePo;
        if (password.equals(user.getPassword())) {
            String id = StringTokenUtil.prefix(snowflake.nextId());
            String token = StringTokenUtil.getToken(username, id);
            userCachePo = toUserPo(user);
            userCachePo.setToken(token);
            userCacheUtil.cacheUser(id, userCachePo);
            // 更新用户信息
            user.setLastLoginTime(new Date());
            updateData(user);
        } else {
            throw new BusinessException(new Result(ResultCodeEnum.AUTH_FAILED, null));
        }
        return userCachePo;
    }

    @Override
    public Page<UserDto> pageUserInfoList(String userName, String phone, Integer pageNum, Integer pageSize) {
        Pageable pageable = PageRequest.of((pageNum - 1), pageSize);

        Page<User> page = userDao.findAll(new Specification<User>() {
            List<Predicate> listPre = new ArrayList<>();

            @Override
            public Predicate toPredicate(Root<User> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
                if (!StringUtils.isEmpty(userName)) {
                    listPre.add(criteriaBuilder.like(root.get("userName").as(String.class), "%" + userName + "%"));
                }
                if (!StringUtils.isEmpty(phone)) {
                    listPre.add(criteriaBuilder.like(root.get("phone").as(String.class), "%" + phone + "%"));
                }
                Predicate[] pre = new Predicate[listPre.size()];
                criteriaQuery.where(listPre.toArray(pre));
                return criteriaBuilder.and(pre);
            }
        }, pageable);
        return new PageImpl<>(toUserDto(page.getContent()), pageable, page.getTotalElements());
    }



    private UserCachePo toUserPo(User user) {
        UserCachePo po = new UserCachePo();
        po.setPhoto(user.getPhoto());
        po.setUserId(user.getId());
        po.setUserName(user.getUserName());
        po.setUuid(user.getUuid());
        return po;
    }

    private List<UserDto> toUserDto(List<User> list) {
        List<UserDto> dtos = new ArrayList<>(list.size());
        list.forEach(user -> {
            UserDto dto = new UserDto();
            BeanUtils.copyProperties(user, dto);
            dtos.add(dto);
        });
        return dtos;
    }
}
